package com.gopay.common.util.compare;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 对比工具类
 * Created by Light on 2016/12/2.
 */
public enum CompareUtils {
    INSTANCE;

    private static final Logger logger = LoggerFactory.getLogger(CompareUtils.class);

    public static CompareResult compare(Object before, Object after){
        try {
            CompareResult compareResult = new CompareResult();
            compareResult.setBeforeJson(JSON.toJSONString(before));
            compareResult.setAfterJson(JSON.toJSONString(after));
            if(compareResult.getBeforeJson().equals(compareResult.getAfterJson())){
            	//相等时也要返回，不然未个性化基础方案的用户，当使用默认通用配置时，无法保存个性化基础方案   edit by fanghw 20170417
                //return null;
            	logger.info("未修改也强制保存--equals");
            	compareResult.setBeforeTranslate("未修改也强制保存:0");
                compareResult.setAfterTranslate("未修改也强制保存:1");
            	return compareResult;
            	
            }
            StringBuilder beforeTranslate = new StringBuilder();
            StringBuilder afterTranslate = new StringBuilder();
            Class clazz = before.getClass();
            Field[] fields = clazz.getDeclaredFields();
            Method[] declaredMethods = clazz.getDeclaredMethods();
            int changeFlag = 0;
            for (Field field : fields) {
                Annotation[] annotations = field.getAnnotations();
                for (Annotation annotation : annotations) {
                    if (annotation instanceof Compare) {
                        int fieldChangeFlag = 0;
                        int equalsMethodFlag = 0;
                        String transMethod;
                        String equalsMethod;
                        Compare compare = (Compare) annotation;
                        if (StringUtils.isBlank(compare.transMethod())) {
                            transMethod = field.getName() + "Translate";
                        } else {
                            transMethod = compare.transMethod();
                        }
                        if (StringUtils.isBlank(compare.equalsMethod())) {
                            equalsMethod = field.getName() + "Equals";
                        } else {
                            equalsMethod = compare.equalsMethod();
                        }
                        field.setAccessible(true);
                        Object valueBefore = field.get(before);
                        Object valueAfter = field.get(after);

                        for (Method method : declaredMethods) {
                            if (equalsMethod.equals(method.getName())) {
                                equalsMethodFlag = 1;
                                method.setAccessible(true);
                                if(!(Boolean)method.invoke(before, valueBefore, valueAfter)){
                                    fieldChangeFlag = 1;
                                    changeFlag = 1;
                                }
                                break;
                            }
                        }

                        if(equalsMethodFlag == 0){
                            if( (valueBefore == null && "".equals(valueAfter)) || ("".equals(valueBefore) && valueAfter == null) ){
                                continue;
                            }

                            if (valueBefore == null) {
                                if (valueAfter != null) {
                                    fieldChangeFlag = 1;
                                    changeFlag = 1;
                                }
                            } else {
                                if (!valueBefore.equals(valueAfter)) {
                                    fieldChangeFlag = 1;
                                    changeFlag = 1;
                                }
                            }
                        }

                        if(fieldChangeFlag == 1){
                            for (Method method : declaredMethods) {
                                if (transMethod.equals(method.getName())) {
                                    method.setAccessible(true);
                                    valueBefore = method.invoke(before, valueBefore);
                                    valueAfter = method.invoke(after, valueAfter);
                                    break;
                                }
                            }
                            beforeTranslate.append(compare.columnName()).append(":").append(valueBefore).append("；");
                            afterTranslate.append(compare.columnName()).append(":").append(valueAfter).append("；");
                        }
                    }
                }
            }
            if(changeFlag == 1){
                compareResult.setBeforeTranslate(beforeTranslate.deleteCharAt(beforeTranslate.length() - 1).toString());
                compareResult.setAfterTranslate(afterTranslate.deleteCharAt(afterTranslate.length() - 1).toString());
                return compareResult;
            }else{
            	//相等时也要返回，不然未个性化基础方案的用户，当使用默认通用配置时，无法保存个性化基础方案   edit by fanghw 20170417
            	logger.info("未修改也强制保存--changeFlag不是1");
            	compareResult.setBeforeTranslate("未修改也强制保存:0");
                compareResult.setAfterTranslate("未修改也强制保存:1");
            	return compareResult;
            }
            
            
        } catch (Exception e){
            logger.error("对比异常",e);
        }
        logger.info("CompareUtils返回null");
        return null;
    }

    public static boolean compareStringList(List<String> listBefore, List<String> listAfter) {
        if(listBefore != null && listAfter != null) {
            if(listBefore.size() == listAfter.size()) {
                List<String> compareBefore = new ArrayList<>();
                compareBefore.addAll(listBefore);
                List<String> compareAfter = new ArrayList<>();
                compareAfter.addAll(listAfter);
                Collections.sort(compareBefore);
                Collections.sort(compareAfter);
                for(int i = 0; i < compareBefore.size(); ++i) {
                    if (!StringUtils.equals(compareBefore.get(i), compareAfter.get(i))) {
                        return false;
                    }
                }
                return true;
            }
        } else if(listBefore == null) {
            if(listAfter == null) {
                return true;
            }
            if(listAfter.size() == 0){
                return true;
            }
        } else if(listBefore.size() == 0) {
            return true;
        }
        return false;
    }

}
